from typing import Dict, List, Union

from flask import Blueprint, request, current_app
from utils import save_config
from pluginUtils.utils.loader import get_comprehensioner, get_reader, load_comprehensioner
from collections import defaultdict

import inspect

from pluginUtils.basic import BasicComprehensionPlugin, BasicReaderPlugin
from utils.docparse import parsedoc

api_blueprint = Blueprint("api_plugin_blueprint", __name__)


@api_blueprint.route("/getpluginreader")
def getpluginreader():
    """
    配置页面。
    :return:
    """
    res = list()
    readertype2pluginobject = current_app.config['readertype2pluginobject']
    config = current_app.config['config']
    for type_, pluginobject in readertype2pluginobject.items():
        if isinstance(pluginobject, BasicReaderPlugin):
            introduction = pluginobject.get_introduction()  # noqa
            success = True
        else:
            introduction = "未成功构造的类。"
            success = False
        # introduction = parsedoc(inspect.getdoc(pluginobject.__init__))[0]
        description, params_, returndoc, examples = parsedoc(inspect.getdoc(pluginobject.__init__))
        sig = inspect.signature(pluginobject.__init__)
        defaultparams = defaultdict(str, {k: v.default for k, v in sig.parameters.items() if v.default != sig.empty})
        if type_ not in config['plugins']['reader']:  # 多类型支持
            continue
        construct_params = config['plugins']['reader'][type_]['construct_params']
        params = list()
        for p, i in enumerate(params_):  # (name, intro) to [name, intro, value]
            if i[0] in construct_params:
                params.append([i[0], i[1].replace("\n", "<br>"), construct_params[i[0]]])
            else:
                params.append([i[0], i[1].replace("\n", "<br>"), defaultparams[i[0]]])

        res.append({
            "type": type_,
            "introduction": introduction.replace("\n", "<br>"),
            "params": {
                "description": description.replace("\n", "<br>"),
                "params": params
            },
            "success": success
        })
    return res


@api_blueprint.route("/getplugincomprehensioner")
def getplugincomprehensioner():
    """
    配置页面。
    :return:
    """
    res = list()
    config = current_app.config['config']
    comprehensionername2pluginobject = current_app.config['comprehensionername2pluginobject']
    for pluginname, pluginobject in comprehensionername2pluginobject.items():
        if isinstance(pluginobject, BasicComprehensionPlugin):
            introduction = pluginobject.get_introduction()  # noqa
            success = True
        else:
            introduction = "未成功构造的类。"
            success = False
        description, params_, returndoc, examples = parsedoc(inspect.getdoc(pluginobject.__init__))
        sig = inspect.signature(pluginobject.__init__)
        defaultparams = defaultdict(str, {k: v.default for k, v in sig.parameters.items() if v.default != sig.empty})
        construct_params = config['plugins']['comprehensioner'][pluginname]['construct_params']
        params = list()
        for p, i in enumerate(params_):  # (name, intro) to [name, intro, value]
            if i[0] in construct_params:
                params.append([i[0], i[1], construct_params[i[0]]])  # .replace("\n", "<br>")
            else:
                params.append([i[0], i[1], defaultparams[i[0]]])  # .replace("\n", "<br>")
        res.append({
            "name": pluginname,
            "introduction": introduction,  # .replace("\n", "<br>"),
            "params": {
                "description": description,  # .replace("\n", "<br>"),
                "params": params
            },
            "success": success
        })
    return res


@api_blueprint.route("/getplugincomprehensionernames")
def getplugincomprehensionernames():
    """
    用于推理页面。
    :return:
    """
    comprehensionername2pluginobject = current_app.config['comprehensionername2pluginobject']
    names = list(comprehensionername2pluginobject.keys())
    successes = list()
    name2parameters: Dict[str, Dict[str, Union[str, List[Dict[str, str]]]]] = dict()
    for p, name in enumerate(names):
        if not isinstance(comprehensionername2pluginobject[name], BasicComprehensionPlugin):
            successes.append(False)
            name2parameters[name] = {
                "success": "False"
            }
            continue
        successes.append(True)
        sig = inspect.signature(comprehensionername2pluginobject[name].inference)
        _, paras, _, _ = parsedoc(inspect.getdoc(comprehensionername2pluginobject[name].inference))
        name2description = dict(paras)
        res = list()
        for k, v in sig.parameters.items():
            para_name = v.name  # 名称
            para_default = v.default  # 默认值
            annotation = v.annotation  # 类型
            description = name2description[para_name]
            if para_name not in ["texts", "question", "explained"]:
                res.append({
                    "name": para_name,
                    "default": para_default,
                    "annotation": annotation.__name__,
                    "description": description,

                })
        name2parameters[name] = {
            "success": "True",
            "parems": res
        }
    res = {
        "name2parameters": name2parameters,
    }
    return res


@api_blueprint.route("/savereaderplugin", methods=['POST'])
def savereaderplugin():
    config = current_app.config['config']
    contents = request.json
    for content in contents:
        type_ = content['type']
        params = content['params']['params']
        config['plugins']['reader'][type_]['construct_params'] = {p[0]: p[2] for p in params}
    save_config(config)
    reader, readertype2pluginobject = get_reader(config)
    current_app.config['reader'] = reader
    current_app.config['readertype2pluginobject'] = readertype2pluginobject
    return "保存成功"


@api_blueprint.route("/savecomprehensionerplugin", methods=['POST'])
def savecomprehensionerplugin():
    config = current_app.config['config']
    contents = request.json
    for content in contents:
        name = content['name']
        params = content['params']['params']
        config['plugins']['comprehensioner'][name]['construct_params'] = {p[0]: p[2] for p in params}
    save_config(config)
    current_app.config['comprehensionername2pluginobject'] = get_comprehensioner(config)
    return "保存成功"


@api_blueprint.route("/loadcomprehensionerplugin")  # 暂时用不到，因为保存后会重新加载所有
def loadcomprehensionerplugin():
    pluginname = request.args['pluginname']
    config = current_app.config['config']
    k, v = load_comprehensioner(config, pluginname)
    comprehensionername2pluginobject = current_app.config["comprehensionername2pluginobject"]
    comprehensionername2pluginobject[k] = v
